package cn.jiayen.comm.generate;


import cn.jiayen.comm.annotation.Description;
import cn.jiayen.comm.util.FileClassLoader;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import javax.persistence.Column;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;

/**
 * Created by jiayen on 2018/5/5.
 * 生成代码实际类 主要根据bean实体生成controller与service与reposity
 */
@Slf4j
public class GenerateCodeLogic {
    /**controller**/
    public static int  CONTROLLER= 0x00000001;

    /**service**/
    public static int  SERVICE= 0x00000002;

    /**service_imp**/
    public static int  SERVICE_IMP= 0x00000003;


    /**repository**/
    public static int  REPOSITORY= 0x00000004;

    /**dto**/
    public static int  DTO= 0x00000005;
    /**vo**/
    public static int  VO= 0x00000006;

    private String controllerPath;
    private String servicePath ;
    private  String serviceImplPath;
    private String repositoryPath;

    private String dtoPath;
    private  String voPath;


    /***实体所在的包名*/
    private String packageName;

    /***基本路径（绝对路径）*/
    private String basePath;

    /***java文件所在路径（绝对路径）*/
    private String filePath;

    /***class文件所在路径（绝对路径）*/
    private String classPath;

    /***临时记录的内容数据 主要针对生成dto/vo*/
    private String content;
    /**class文件的的上级文件夹名称  这里默认为target**/
    private String classPathSrcPath;
    public GenerateCodeLogic(String basePath, String packageName, String classPathSrcPath){
            this.classPathSrcPath=classPathSrcPath;
            this.basePath=basePath;
            this.packageName =packageName;
            this.filePath = packageNameToPath(packageName);
            this.classPath = basePath.substring(0,basePath.lastIndexOf("src"))+classPathSrcPath+File.separatorChar+"classes";
    }

    public void startGenerate(){
        log.info("================根据路径"+filePath+"====开始生成============");
        try {
            File file = new File(filePath);
            if(file.exists()){
                //创建包名如果不存在
               mkPagekageName(file);
               File[] files =  file.listFiles();
                log.info("=================类路径:"+classPath+"====开始生成加载类===============");
               File classFile = new File(classPath);

               //创建类加载器
//                URI url = classFile.toURI();
//                URL[] urls = {url.toURL()};
//                FileURIClassLoader classLoader = new FileURIClassLoader(urls);
                FileClassLoader classLoader = new FileClassLoader(classPath);
                for (File beanFile:files ) {
                    String fileName = beanFile.getName();
                    fileName=fileName.substring(0,fileName.indexOf("."));
                    log.info("======文件名称===="+packageName+"."+fileName+".class=====================");
                    //实例化对象
                    Class<?> clazz = classLoader.loadClass(packageName+"."+fileName);
                    log.info("实例化:"+clazz.newInstance().toString());
                    //生成模板java文件
                    generateJavaCode(clazz);
                    //生成模板wenjian
                    generateCode(fileName);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /***
     * 生成模板java文件
     * @param clazz
     */
    private void generateJavaCode(Class<?> clazz) {
      Field[] fields = clazz.getDeclaredFields();
        StringBuilder sb = new StringBuilder();
        for (Field  f:fields) {
            String name = f.getName();
            String type =f.getType().getSimpleName();
//            获取注解
            try {
                Description column = f.getAnnotation(Description.class);
                String viewAnnotation = "@ApiModelProperty(notes = \""+column.value()+"\")";
                sb.append("        ").append(viewAnnotation).append("\t\r");
            }catch (Exception e){
                log.error("错误的生成注解:",e);
            }
            String viewField = "private "+type+"  "+name+";";
            sb .append("        ").append(viewField).append("\r\r");
        }
        String name = clazz.getSimpleName();
        this.content=sb.toString();
        log.info("========code=========="+sb.toString());
        String basePack = packageName.substring(0,packageName.lastIndexOf("."));
        log.info("========开始创建dto文件==========");
        generateCodeByPath(dtoPath+"/"+name+"DTO.java",DTO,"/template/dto.java",name,basePack);
        log.info("========开始创建vo文件==========");
        generateCodeByPath(voPath+"/"+name+"VO.java",DTO,"/template/vo.java",name,basePack);
    }

    /**
     * 类文件的完全路径
     * @param packageName
     * @return
     */
    private String packageNameToPath(String packageName) {
        return basePath + packageName.replace('.', File.separatorChar)+ File.separatorChar;
    }
    /***
     * 开始生成代码
     * @param name
     */
    private void generateCode(String name) throws IOException {
        String basePack = packageName.substring(0,packageName.lastIndexOf("."));
        //创建contoller
        String cPath  = controllerPath+"/"+name+"Controller.java";
         generateCodeByPath(cPath,CONTROLLER,"/template/controller.java",name,basePack);

        //创建service
        String sPath  = servicePath+"/"+name+"Service.java";
        generateCodeByPath(sPath,SERVICE,"/template/service.java",name,basePack);

        //创建serviceImpl
        String sImplPath  = serviceImplPath+"/"+name+"ServiceImpl.java";
        generateCodeByPath(sImplPath,SERVICE_IMP,"/template/serviceImpl.java",name,basePack);

        //创建repository
        String rPath  = repositoryPath+"/"+name+"Repository.java";
        generateCodeByPath(rPath,REPOSITORY,"/template/repository.java",name,basePack);
    }

    /***
     * 处理生成controller内容
     * @param basePack
     * @param name
     * @param file
     * @throws IOException
     */
    private void handCodeContent(String basePack, String name, File file,String templatePath,int type) throws IOException {
        InputStream controllerInput = this.getClass().getResourceAsStream(templatePath);
        byte[] controllerBuf = new byte[controllerInput.available()];
        controllerInput.read(controllerBuf);
        String contentStr = new String(controllerBuf,"utf-8");
        contentStr = getControllerContent(basePack, name, contentStr);
        FileOutputStream outputStream = new FileOutputStream(file);
        outputStream.write(contentStr.getBytes());
    }

    /***
     * 获取controller内容
     * @param basePack
     * @param name
     * @param controllerStr
     * @return
     */
    private String getControllerContent(String basePack, String name, String controllerStr) {
        controllerStr = controllerStr
                .replaceAll("\\$\\{base_pack}",basePack)
                .replaceAll("\\$\\{bean_pack}",packageName+"."+name)
                .replaceAll("\\$\\{name}",name)
                .replaceAll("\\$\\{m_name}",name.toLowerCase())
                ;
        if(!StringUtils.isEmpty(content)){
            controllerStr = controllerStr
                    .replaceAll("\\$\\{content}",content);
        }
        return controllerStr;
    }

    /**
     * 生成具体的类
     * @param path
     */
    private File generateCodeByPath(String path,int type,String templatePath,String name,String basePack) {
        log.info("==========创建文件路径==========="+path+"=========成功========");
        File file = new File(path);
        if(!file.exists()){
            try {
                file.createNewFile();
                handCodeContent(basePack, name, file,templatePath,type);
                log.info("==========创建==========="+file.getName()+"=========成功========");
            } catch (IOException e) {
                e.printStackTrace();
                log.info("==========创建==========="+file.getName()+"=========失败========");
            }
        }else{
            log.info("==========class文件==========="+file.getName()+"=========已经存在========");
        }
        return  file;
    }

    /**
     * 根据置顶的bean路径创建包名
     * @param file
     */
    private void mkPagekageName(File file) {
      String parentPath =  file.getParent();
       controllerPath = parentPath+"/controller";
       servicePath = parentPath+"/service";
       serviceImplPath = servicePath+"/impl";
       repositoryPath = parentPath+"/repository";
       dtoPath = parentPath+"/views/dto";
       voPath=parentPath+"/views/vo";

      File tempFile = new File(controllerPath);
      if(!tempFile.exists()){
          tempFile.mkdirs();
          log.info("===========创建contoller包完成=============");
      }
        tempFile = new File(servicePath);
        if(!tempFile.exists()){
            tempFile.mkdirs();
            log.info("===========创建service包完成=============");
        }

        tempFile = new File(serviceImplPath);
        if(!tempFile.exists()){
            tempFile.mkdirs();
            log.info("===========创建service impl包完成=============");
        }

        tempFile = new File(repositoryPath);
        if(!tempFile.exists()){
            tempFile.mkdirs();
            log.info("===========创建repository包完成=============");
        }

        tempFile = new File(dtoPath);
        if(!tempFile.exists()){
            tempFile.mkdirs();
            log.info("===========创建dto包完成=============");
        }

        tempFile = new File(voPath);
        if(!tempFile.exists()){
            tempFile.mkdirs();
            log.info("===========创建vo包完成=============");
        }
    }

    public static  void main(String[] args){
        String basePath ="D:\\gitwork\\rd-maven-plugin\\option-maven-plugin\\src\\main\\java\\";
        String packageName = "cn.jiayen.bean";
        GenerateCodeLogic logic = new GenerateCodeLogic(basePath,packageName,"target");
        logic.startGenerate();
        //D:\gitwork\rd-maven-plugin\option-maven-plugin\target
    }
}
